### FUNCOES ###

# Funcao que da a probabilidade dada uma tabela, uma classe e uma frase

getProbability = function(tabela, classe, frase){
  
  tamanhoTotal = length(tabela);
  
  countFrase = 0;
  countTotal = 0;
  tabela_classe = tabela[[classe]];
  
  if(!is.null(tabela_classe)){
    countTotal = tabela_classe$total;
    tabela_count = tabela[[classe]]$contador[[frase]];
    if(!is.null(tabela_count)){
      countFrase = tabela_count;
    }
  }
  
  prob = (1 + countFrase) / (countTotal + tamanhoTotal);
  
  return(prob);
}

# Funcao que classifica um texto

classify = function(text, dictionary, bigramTable, trigramTable, quadgramTable,cor_mat,history_cor){
  
  text = tolower(x=text);
  class = c('','','');
  prob = c(0,0,0);
  totalDict = sum(dictionary) + length(dictionary);
  
  # Usa a formula do naive bayes:
  # p(c|frase) = p(c) * p(bigrama|c) * p(trigrama|c) * p(quadgrama|c)
  # Ajustada para evitar multiplicacoes por 0.
  
  textSplitted = unlist(strsplit(text, split=" "));
  
  textBi = textSplitted[3];
  textTri = paste(textSplitted[2], textSplitted[3]);
  textQuad = paste(textSplitted[1], textSplitted[2], textSplitted[3]);
  
  history_cor=addWordToHistoric(alfa=0.90,historic=history_cor,cor_mat=cor_mat,word=textSplitted[3])

  
  for(i in names(sort(history_cor,decreasing=TRUE))){
    
    if( i %in% rownames(dictionary))
      prob1 =(1 + dictionary[i,1])/totalDict
    else
      prob1 = 1/totalDict;
  
    #probBi=1;
    #probTri=1;
    probBi = getProbability(tabela = bigramTable, classe = i, frase = textBi);
    probTri = getProbability(tabela = trigramTable, classe = i, frase = textTri);
    probQuad = getProbability(tabela = quadgramTable, classe = i, frase = textQuad);
    
    #print(history_cor[i])
    
    
    #
    prob_temp =  (1+history_cor[[i]])*prob1 * probBi * probTri * probQuad;
    class_temp = i;
    
    if(prob_temp > prob[[1]]){
      swap_class = class[[1]];
      swap_prob = prob[[1]];
      
      class[[1]] = class_temp;
      prob[[1]] = prob_temp;
      
      class_temp = swap_class;
      prob_temp = swap_prob;
    }
    
    if(prob_temp > prob[[2]]){
      swap_class = class[[2]];
      swap_prob = prob[[2]];
      
      class[[2]] = class_temp;
      prob[[2]] = prob_temp;
      
      class_temp = swap_class;
      prob_temp = swap_prob;
    }
    
    if(prob_temp > prob[[3]]){
      swap_class = class[[3]];
      swap_prob = prob[[3]];
      
      class[[3]] = class_temp;
      prob[[3]] = prob_temp;
      
      class_temp = swap_class;
      prob_temp = swap_prob;
    }
    
  }
  
  return (list(class,prob,history_cor=history_cor));
}

errorEvaluator=function(dictionary,bigram,trigram,quadgram,fourgramTestTable,cor_mat,history_cor){
  
  total=0;
  correct=0;
  correct2=0;
  
  #answers = data.frame(colum)
  
  for(text in rownames(fourgramTestTable)){
    splited=unlist(strsplit(text," "))
    
    #print(paste("Tentando prever",splited[1:3],collapse=" "))
    
    #print(paste(splited[1:4],collapse=" "))
    result=classify(text=paste(splited[1:3],collapse=" "),dictionary=dictionary,
                    bigramTable=bigram,trigramTable=trigram,quadgramTable=quadgram,cor_mat, history_cor)
    
    history_cor=result$history_cor
    
    total=total + fourgramTestTable[text,1]
    
    
    if(splited[4] %in% result[[1]]){
      correct = correct + fourgramTestTable[text,1]
    }
    
    
    print("Resultado parcial:")
    print(paste("Corretas:",correct , "Total:" ,total , "%:",correct/total))
    
  }
  
  return (list(correct=correct,total=total,fraction=correct/total));
}

gramSimplifier = function(ngram, n){
  nrows=nrow(ngram)
  splited_words=strsplit(rownames(ngram)," ")
  
  #Pegamos as classes e setamos como names da nossa lista
  new_ngram=as.list(sapply(unique(unlist(splited_words)[1:nrows*n]),function(x) NULL))
  
  #print(names(new_ngram));
  
  #inicializamos todos os elementos
  new_ngram[]=list(list(total=0,contador=list()))
  
  for(text in splited_words){
    #Fazemos um join dos n-1 primeiro termos
    prefix=paste(text[1:(n-1)],collapse=" ")
    key=paste(text,collapse=" ")
    
    new_ngram[[text[n]]]$total=ngram[[key,1]]+new_ngram[[text[n]]]$total
    
    if(is.null(new_ngram[text[n]]$contador[prefix])){
      new_ngram[[text[n]]]$contador[[prefix]]=0
    }
    
    new_ngram[[text[n]]]$contador[[prefix]]=ngram[[key,1]]+new_ngram[[text[n]]]$contador[[prefix]]
    
  }
  
  return(new_ngram)
}


getCovarianceMatriz=function(dictionary, corpus, customStopWords){
  #Convertemos todas as letras para o minúsculo
  corpus <- tm_map(corpus,tolower);
  #Removemos as stopwords dos textos
  corpus <- tm_map(corpus,removeWords,customStopWords);
  #Removemos a pontuação do texto
  corpus <- tm_map(corpus,removePunctuation);
  #Removemos a pontuação das stopwords para pegar casos
  #como "dont" e "cant"
  customStopWords=removePunctuation(customStopWords)
  #Removemos mais uma vez nosso novo conjunto de stop
  #words
  corpus <- tm_map(corpus,removeWords,customStopWords);
  
  #Removemos o espaços em branco extras
  #obs: na pratica não fará diferença, mas permite uma
  #melhor vizualização do texto durante a faze de debug
  #corpus <- tm_map(corpus, stripWhitespace);
  
  doc=DocumentTermMatrix(corpus,
                         list(weighting = weightTfIdf,
                              removeNumbers=TRUE
                         ));
  
  
  return (cor(cor(as.matrix(doc))));
}


addWordToHistoric = function(alfa, historic, cor_mat,word){
  if(word %in% rownames(cor_mat)){
    old_word_value=historic[word]
    historic=(alfa)*historic+ (1-alfa)*cor_mat[word,]
    historic[word]=old_word_value
  }
  
  return (historic)
}